<template>
    <div id="iviewBg"></div>
</template>

<script>
import * as THREE from "three";
import { onMounted } from "vue";
export default {
    props: {
        //控制x轴波浪的长度
        amountX: {
            type: Number,
            default: 120,
        },
        //控制y轴波浪的长度
        amountY: {
            type: Number,
            default: 100,
        },
        //控制点颜色
        color: {
            type: String,
            default: "#097bdb",
        },
        //控制波浪高度的位置
        top: {
            type: Number,
            default: 200,
        },
    },

    setup(props) {
        const SEPARATION = 100;

        // let stats;
        let container, camera, scene, renderer;

        let particles,
            count = 0;

        let mouseX = 0;

        let windowHalfX = window.innerWidth / 2;

        function init() {
            container = document.createElement("div");
            document.getElementById("iviewBg").appendChild(container);

            //创建透视相机
            camera = new THREE.PerspectiveCamera(
                75, //摄像机视锥体垂直视野角度
                window.innerWidth / window.innerHeight, //摄像机视锥体长宽比
                1, //摄像机视锥体近端面
                10000 //摄像机视锥体远端面
            );

            //设置相机z轴视野
            camera.position.z = 1000;

            //创建场景
            scene = new THREE.Scene();

            const numParticles = props.amountX * props.amountY;

            const positions = new Float32Array(numParticles * 3);
            const scales = new Float32Array(numParticles);

            let i = 0,
                j = 0;

            // 初始化粒子位置和大小
            for (let ix = 0; ix < props.amountX; ix++) {
                for (let iy = 0; iy < props.amountY; iy++) {
                    positions[i] = ix * SEPARATION - (props.amountX * SEPARATION) / 2; // x
                    positions[i + 1] = 0; // y
                    positions[i + 2] = iy * SEPARATION - (props.amountY * SEPARATION) / 2; // z
                    scales[j] = 1;
                    i += 3;
                    j++;
                }
            }

            //是面片、线或点几何体的有效表述。包括顶点位置，面片索引、法相量、颜色值、UV 坐标和自定义缓存属性值。使用 BufferGeometry 可以有效减少向 GPU 传输上述数据所需的开销
            const geometry = new THREE.BufferGeometry();
            geometry.setAttribute(
                "position",
                new THREE.BufferAttribute(positions, 3)
            );
            geometry.setAttribute("scale", new THREE.BufferAttribute(scales, 1));

            //着色器材质(ShaderMaterial),设置球的大小，颜色，等
            const material = new THREE.ShaderMaterial({
                uniforms: {
                    //设置球的颜色
                    color: { value: new THREE.Color(props.color) },
                },
                //控制球的大小
                vertexShader:
                    "attribute float scale; void main() {vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );gl_PointSize = scale * ( 300.0 / - mvPosition.z );gl_Position = projectionMatrix * mvPosition;}",
                fragmentShader:
                    "uniform vec3 color;void main() {if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;gl_FragColor = vec4( color, 1.0 );}",
            });

            //一个用于显示点的类。
            particles = new THREE.Points(geometry, material);
            //往场景中添加点
            scene.add(particles);

            //alpha - canvas是否包含alpha (透明度)。默认为 false。
            //渲染器的背景色默认为黑色，设置渲染器的背景色为透明
            renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setClearAlpha(0);
            renderer.setSize(window.innerWidth, window.innerHeight);
            container.appendChild(renderer.domElement);

            //显示右上角fps框
            // stats = new Stats();
            //   container.appendChild(stats.dom);

            container.style.touchAction = "none";
            //监听鼠标移动事件
            container.addEventListener("pointermove", onPointerMove);

            //调整波浪的位置
            container.style.position = "relative";
            container.style.top = `${props.top}px`;

            window.addEventListener("resize", onWindowResize);
        }

        function render() {
            camera.position.x += (mouseX - camera.position.x) * 0.05;
            camera.position.y = 400;
            camera.lookAt(scene.position);

            const positions = particles.geometry.attributes.position.array;
            const scales = particles.geometry.attributes.scale.array;

            // 设置粒子位置和大小
            let i = 0,
                j = 0;
            for (let ix = 0; ix < props.amountX; ix++) {
                for (let iy = 0; iy < props.amountY; iy++) {
                    positions[i + 1] =
                        Math.sin((ix + count) * 0.3) * 50 +
                        Math.sin((iy + count) * 0.5) * 50;

                    scales[j] =
                        (Math.sin((ix + count) * 0.3) + 1) * 10 +
                        (Math.sin((iy + count) * 0.5) + 1) * 10;

                    i += 3;
                    j++;
                }
            }

            particles.geometry.attributes.position.needsUpdate = true;
            particles.geometry.attributes.scale.needsUpdate = true;

            renderer.render(scene, camera);

            count += 0.1;
        }

        function onWindowResize() {
            windowHalfX = window.innerWidth / 2;
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        //监听鼠标移动事件
        function onPointerMove(event) {
            console.log(event);
            if (event.isPrimary === false) return;
            mouseX = event.clientX - windowHalfX;
        }

        function animate() {
            requestAnimationFrame(animate);
            render();
        }

        onMounted(() => {
            init();
            animate();
        });
        return {};
    },
};
</script>

<style lang="scss" scoped>
#iviewBg {
    width: 100%;
    height: 100vh;
    overflow: hidden;
    position: absolute;
    z-index: 1;
}
</style>
